﻿using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Xml.Linq;
using Red.Controls.Tile;
using Red.Controls.Utils;
using Red.Core;
using Red.Launcher.Utilities;

namespace Red.Launcher.ViewModels.ExternalApplications
{
    public class Application : ViewModel, ICloneable, IDragCreateViewModel, IStringProvider<Tile.IStrings>
    {
        #region Public Types

        public class EnvironmentVariable
        {
            #region Public Properties

            public string Key { get; set; }
            public string Value { get; set; }

            #endregion Public Properties
        }

        #endregion Public Types

        #region Private Data

        private string _name;
        private FilePath _path = new FilePath();
        private string _icon;
        private FilePath _commandLineParams = new FilePath();

        #endregion Private Data

        #region Public Properties

        public string Name
        {
            get
            {
                if ( string.IsNullOrEmpty( _name ) )
                {
                    try
                    {
                        return System.IO.Path.GetFileName( Path );
                    }
                    catch( ArgumentException )
                    {
                        // User typed an invalid path, just ignore it
                    }
                }

                return _name;
            }
            set
            {
                if ( _name != value )
                {
                    _name = value;
                    OnPropertyChanged();
                }
            }
        }

        public string Path
        {
            get { return _path; }
            set
            {
                if ( _path != value )
                {
                    _path = value;
                    OnPropertyChanged();

                    if ( string.IsNullOrEmpty( _name ) )
                    {
                        OnPropertyChanged( "Name" );
                    }
                }
            }
        }

        public string Icon
        {
            get { return _icon; }
            set
            {
                if ( _icon != value )
                {
                    _icon = value;
                    OnPropertyChanged();
                }
            }
        }

        public string CommandLineParameters
        {
            get { return _commandLineParams; }
            set
            {
                if ( _commandLineParams != value )
                {
                    _commandLineParams = value;
                    OnPropertyChanged();
                }
            }
        }

        public string ResolvedPath => _path.ResolvedPath;
        public string ResolvedCommandLineParameters => _commandLineParams.ResolvedPath;

        public ObservableCollection<EnvironmentVariable> EnvironmentVariables { get; set; }

        #endregion Public Properties

        #region C-Tor

        public Application()
        {
            EnvironmentVariables = new ObservableCollection<EnvironmentVariable>();
        }

        #endregion C-Tor

        #region Public Methods

        /// <summary>
        /// Deep copy
        /// </summary>
        public object Clone()
        {
            Application clone = (Application)MemberwiseClone();

            clone.EnvironmentVariables = new ObservableCollection<EnvironmentVariable>( EnvironmentVariables );

            return clone;
        }

        public void Copy( Application other )
        {
            Name = other.Name;
            Path = other.Path;
            Icon = other.Icon;
            CommandLineParameters = other.CommandLineParameters;
            EnvironmentVariables = new ObservableCollection<EnvironmentVariable>( other.EnvironmentVariables );
        }

        #region Serialisation

        public XElement ToXml()
        {
            XElement root = new XElement( "Application" );

            XmlHelper.AddAttribute( root, "Name", Name );
            XmlHelper.AddAttribute( root, "Path", Path );
            XmlHelper.AddAttribute( root, "Icon", Icon );
            XmlHelper.AddAttribute( root, "CommandLineParameters", CommandLineParameters );

            if ( EnvironmentVariables.Count > 0 )
            {
                XElement evRoot = new XElement( "EnvironmentVariables" );

                foreach ( EnvironmentVariable ev in EnvironmentVariables )
                {
                    XElement evElement = new XElement( "EnvironmentVariable" );

                    if ( XmlHelper.AddAttribute( evElement, "Key", ev.Key ) && XmlHelper.AddAttribute( evElement, "Value", ev.Value ) )
                    {
                        evRoot.Add( evElement );
                    }
                }

                root.Add( evRoot );
            }

            return root;
        }

        public void FromXml( XElement root )
        {
            if ( root.Name == "Application" )
            {
                Name = XmlHelper.GetAttribute( root, "Name" );
                Path = XmlHelper.GetAttribute( root, "Path" );
                Icon = XmlHelper.GetAttribute( root, "Icon" );
                CommandLineParameters = XmlHelper.GetAttribute( root, "CommandLineParameters" );

                XElement evRoot = root.Element( "EnvironmentVariables" );
                if ( evRoot != null )
                {
                    foreach ( XElement child in evRoot.Elements() )
                    {
                        string key = XmlHelper.GetAttribute( child, "Key" );
                        string value = XmlHelper.GetAttribute( child, "Value" );

                        if ( key != null && value != null )
                        {
                            EnvironmentVariable ev = new EnvironmentVariable()
                            {
                                Key = key,
                                Value = value
                            };

                            EnvironmentVariables.Add( ev );
                        }
                    }
                }
            }
        }

        #endregion Serialisation

        #region IDragCreateViewModel

        public object CreateDragViewModel( Type type )
        {
            if ( type == typeof( Tile ) )
            {
                return new Tile()
                {
                    Function = Path,
                    FunctionGroup = "application",
                    Icon = Icon,
                    StringProvider = this
                };
            }

            return null;
        }

        #endregion IDragCreateViewModel

        #endregion Public Methods

        #region IStringProvider<Tile.IStrings>

        public Tile.IStrings GetValue( string key )
        {
            Debug.Assert( key == $"application.{Path}" );

            return new Tile.Strings()
            {
                Key = key,
                Header = Name,
                Description = Path
            };
        }

        #endregion IStringProvider<Tile.IStrings>
    }
}
